# pip install cairosvg pillow

import json
import os


def build_svg(bg=None, hair=None, body=None, cloth=None, face=None, eye=None, eyebrow=None, mouth=None, nose=None, feature=None, glass=None, hat=None, hobby=None):
    svg_content = '''<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">'''
    
    # background
    svg_content += process_path_to_path(bg)
    # back hair
    # hair是否存在backPath
    if(hair is not None and 'backPath' in hair):
        svg_content += process_frontPath_to_path(hair['backPath'])
    # body
    body = [{
                "type": "path",
                "style": [{
                    "attr": "class",
                    "val": "bodyColor"
                }, {
                    "attr": "stroke-linejoin",
                    "val": "round"
                }, {
                    "attr": "stroke-linecap",
                    "val": "round"
                }, {
                    "attr": "class",
                    "val": "faceColor"
                }, {
                    "attr": "stroke",
                    "val": "#000"
                }, {
                    "attr": "stroke-width",
                    "val": 12
                }, {
                    "attr": "d",
                    "val": "M381.354,521.35c9.468,2.759,16.571,5.523,21.301,9.071c4.734,3.158,9.469,9.463,13.806,18.146c7.889,14.596,16.17,37.471,24.059,68.628c5.524,20.119,9.86,39.842,13.02,59.563c3.551,19.722,5.127,35.499,4.729,46.15c7.104,12.616,10.259,26.027,10.259,40.626c-0.397,17.748-7.493,28.788-21.298,32.344c-15.777,4.729-26.433,2.36-32.74-5.917c-5.917-8.679-4.73-21.693,3.158-38.657c-16.174-78.886-24.852-124.245-26.034-136.472l-9.072,130.951l19.723,126.612c51.275,22.091,61.923,42.599,31.554,60.743c-22.88,13.408-49.305,3.151-80.074-31.554l-16.563-154.623H305.23L276.044,894.09c-28.399,45.36-56.01,56.799-82.831,33.923c-26.825-22.881-15.385-41.416,34.312-55.617l27.218-125.434l-8.679-132.13c-15.777,50.486-26.428,91.508-32.736,121.881c13.413,52.063,1.579,69.812-35.5,53.248c-14.987-6.706-20.904-20.511-17.356-41.025c1.187-6.703,3.159-13.411,6.313-20.508c3.155-11.438,7.1-27.611,12.226-48.907c4.735-20.909,10.258-41.813,16.96-62.325c9.468-30.367,18.538-53.247,26.824-68.628c6.703-13.413,13.409-21.3,19.326-23.667c9.467-3.943,21.693-7.098,37.471-9.069c15.384-1.972,31.162-2.763,46.542-1.972C341.912,514.247,360.45,516.616,381.354,521.35"
                }]
            }]
    svg_content += process_path_to_path(body)
    # cloth
    svg_content += process_path_to_path(cloth)
    # face
    svg_content += process_path_to_path(face)
    # eye
    svg_content += process_path_to_path(eye)
    # eyeBrow
    svg_content += process_path_to_path(eyebrow)
    # mouth
    svg_content += process_path_to_path(mouth)
    # nose
    svg_content += process_path_to_path(nose)
    # feature
    svg_content += process_path_to_path(feature)
    # glass
    svg_content += process_path_to_path(glass)
    # front hair
    if(hair is not None and 'frontPath' in hair):
        svg_content += process_frontPath_to_path(hair['frontPath'])
    # hat
    svg_content += process_path_to_path(hat)
    # hobby
    svg_content += process_path_to_path(hobby)

    svg_content += '</svg>'
    return svg_content


def process_frontPath_to_path(svg_paths):
    
    # 创建SVG文件并写入数据
    svg_content = ''
    if(svg_paths is None):
        return svg_content

    for path in svg_paths:
        
        svg_content += process_ele(path)
        
    return svg_content

def process_path_to_path(svg_paths):
    # 创建SVG文件并写入数据
    svg_content = ''
    if(svg_paths is None):
        return svg_content
    
    # 遍历svg_paths中的每个路径 将d作为path
    for path in svg_paths:
        svg_content += process_ele(path)
    return svg_content

def process_ele(path):
    svg_content = ''
    if 'type' not in path:
        styles = 'style="' + ';'.join(f'{style["attr"]}:{style["val"]}' for style in path['style']) + '"'
        svg_content += f'<path d="{path["path"]}" {styles}/>\n'
            
    elif path['type'] == 'path':
            #'''"path":[
            # 			{
            # 				"type":"path",
            # 				"style":[{"attr":"class","val":"faceColor"},{"attr":"d","val":"M150.21,428.225c-28.245,0-51.225-22.307-51.225-49.725c0-31.936,16.953-51.001,45.348-51.001c2.07,0,4.231,0.102,6.421,0.301c28.786,2.625,49.68,23.737,49.68,50.2C200.435,405.694,177.904,428.225,150.21,428.225zM489.79,428.225c-27.694,0-50.225-22.53-50.225-50.225c0-26.463,20.894-47.575,49.68-50.2c2.19-0.199,4.351-0.301,6.421-0.301c28.396,0,45.349,19.065,45.349,51.001C541.015,405.918,518.035,428.225,489.79,428.225z"}]
            # 			}
            # 		]'''
            styles = ''  # 初始化样式列表
            d = None  # 初始化d属性为None，稍后在循环中赋值
            for style in path['style']:
                if style['attr'] == 'class':
                    #faceColor
                    styles+=(f'fill:#fedcb7;')  # 累加样式到列表
                elif style['attr'] != 'd':
                    styles+=(f'{style["attr"]}:{style["val"]};')  # 累加样式到列表
                else:
                    d = style["val"]  # 赋值d属性
            
            svg_content += f'<path d="{d}" style= "{styles}"/>\n'
    elif path['type'] == 'ellipse':
        # "path":[
        # 	{
        # 		"type":"ellipse",
        # 		"style":[{"attr":"fill","val":"none"},{"attr":"stroke-width","val":11},{"attr":"stroke","val":"#000"},{"attr":"cx","val":225.508},{"attr":"cy","val":354.699},{"attr":"rx","val":51.659},{"attr":"ry","val":50.885}]
        # 	}]
        
        # target
        # <ellipse cx="100" cy="100" rx="80" ry="50" fill="lightblue" stroke="darkblue" stroke-width="3">
        attrs = ''
        for style in path['style']:
            attrs += (f'{style["attr"]}="{style["val"]}" ')
            
        svg_content += f'<ellipse {attrs}/>\n'
    
    elif path['type'] == 'rect':
        # "path":[
        # 	{
        # 		"type":"rect",
        # 		"style":[{"attr":"fill","val":"none"},{"attr":"stroke-width","val":1},{"attr":"stroke","val":"#000"},{"attr":"x","val":225.508},{"attr":"y","val":354.699},{"attr":"width","val":51.659},{"attr":"height","val":50.885}]
        # 	}]
        
        # target
        # <rect x="100" y="100" width="80" height="50" fill="lightblue" stroke="darkblue" stroke-width="3" />
        attrs = ''
        for style in path['style']:
            attrs += (f'{style["attr"]}="{style["val"]}" ')
            
        svg_content += f'<rect {attrs}/>\n'
        
    elif path['type'] == 'circle':
        # "path":[
        # 	{
        # 		"type":"circle",
        # 		"style":[{"attr":"fill","val":"none"},{"attr":"stroke-width","val":1},{"attr":"stroke","val":"#000"},{"attr":"cx","val":225.508},{"attr":"cy","val":354.699},{"attr":"r","val":50.88
        # 	}]
        # }]

        # target
        # <circle cx="100" cy="100" r="80" fill="lightblue" stroke="darkblue" stroke-width="3" />
        attrs = ''
        for style in path['style']:
            attrs += (f'{style["attr"]}="{style["val"]}" ')
            
        svg_content += f'<circle {attrs}/>\n'
    elif path['type'] == 'polygon':
        # "path":[
        # 	{
        # 		"type":"polygon",
        # 		"style":[{"attr":"fill","val":"none"},{"attr":"stroke-width","val":1},{"attr":"stroke","val":"#000"},{"attr":"points","val":"225.508,354.699 277.279,354.699 27.734,304.814 
        # 	}]
        # }]

        # target
        # <polygon points="100,100 180,100 100,180" fill="lightblue" stroke="darkblue" stroke-width="3" />
        attrs = ''
        for style in path['style']:
            attrs += (f'{style["attr"]}="{style["val"]}" ')
            
        svg_content += f'<polygon {attrs}/>\n'
    elif path['type'] == 'polyline':
        # "path":[
        # 	{
        # 		"type":"polyline",
        # 		"style":[{"attr":"fill","val":"none"},{"attr":"stroke-width","val":1},{"attr":"stroke","val":"#000"},{"attr":"points","val":"225.508,354.699 277.279,354.699 27.734,304.814     
        # 	}]
        # }]

        # target
        # <polyline points="100,100 180,100 100,180" fill="lightblue" stroke="darkblue" stroke-width="3" />
        attrs = ''
        for style in path['style']:
            attrs += (f'{style["attr"]}="{style["val"]}" ')
            
        svg_content += f'<polyline {attrs}/>\n'
        
    elif path['type'] == 'line':
        # "path":[
        # 	{
        # 		"type":"line",
        # 		"style":[{"attr":"fill","val":"none"},{"attr":"stroke-width","val":1},{"attr":"stroke","val":"#000"},{"attr":"x1","val":225.508},{"attr":"y1","val":354.699},{"attr":"x2","val":277.279},{"attr":"y2","val":354.699}]
        # 	}]

        # target
        # <line x1="100" y1="100" x2="180" y2="100" fill="lightblue" stroke="darkblue" stroke-width="3" />
        attrs = ''
        for style in path['style']:
            attrs += (f'{style["attr"]}="{style["val"]}" ')
            
        svg_content += f'<line {attrs}/>\n'
    return svg_content


def getHair(id):
    with open('data\\hair\\hair_1.json', 'r') as file:
        data = file.read()
    hairData = json.loads(data)
    
    return hairData[id]['frontSide']

def getCloth(id):
    with open('data\\cloth\\cloth_2.json', 'r') as file:
        cloth = file.read()
    clothData = json.loads(cloth)
    
    return clothData[id]['frontSide']['path']

def getEye(id):
    with open('data\\eye\\eye.json', 'r') as file:
        eyes = file.read()
    eyesData = json.loads(eyes)
    
    return eyesData[id]['frontSide']['path']

def getEyebrow(id):
    with open('data\\eyebrow\\eyebrow.json', 'r') as file:
        eyebrow = file.read()
    eyebrowData = json.loads(eyebrow)
    
    return eyebrowData[id]['frontSide']['path']

def getFace(id):
    with open('data\\face\\face.json', 'r') as file:
        face = file.read()
    faceData = json.loads(face)
    
    return faceData[id]['frontSide']['path']

def getFeature(id):
    with open('data\\feature\\feature.json', 'r') as file:
        feature = file.read()
    featureData = json.loads(feature)
    
    return featureData[id]['frontSide']['path']

def getGlass(id):
    with open('data\\glass\\glass.json', 'r') as file:
        glass = file.read()
    glassData = json.loads(glass)
    
    return glassData[id]['frontSide']['path']

def getHat(id):
    with open('data\\hat\\hat_1.json', 'r') as file:
        hat = file.read()
    hatData = json.loads(hat)
    
    return hatData[id]['frontSide']['path']

def getHobby(id):
    with open('data\\hobby\\hobby_1.json', 'r') as file:
        hobby = file.read()
    hobbyData = json.loads(hobby)
    
    return hobbyData[id]['frontSide']['path']

def getMouth(id):
    with open('data\\mouth\\mouth.json', 'r') as file:
        mouth = file.read()
    mouthData = json.loads(mouth)
    
    return mouthData[id]['frontSide']['path']

def getNose(id):
    with open('data\\nose\\nose.json', 'r') as file:
        nose = file.read()
    noseData = json.loads(nose)
    
    return noseData[id]['frontSide']['path']


def genClothes():
    #合并cloth文件
    # 遍历data\\cloth文件夹下的所有文件
    clothAllData = {}
    for filename in os.listdir("data\\cloth"):
        if filename.endswith(".json"):
            with open(os.path.join("data\\cloth", filename), 'r') as file:
                content = file.read()
                clothData = json.loads(content)
                for key, value in clothData.items():
                    clothAllData[key] = value
                    svgStr = build_svg(cloth=value['frontSide']['path'])
                    # svg 转为 png
                    # png_data = cairosvg.svg2png(bytestring = svgStr)
                    # image = Image.open(io.BytesIO(png_data.encode()))
                    # image.save(f'images\\cloth\\{key}.png')
                    with open(f'images\\cloth\\{key}.svg', 'w') as svgFile:
                        svgFile.write(svgStr)
        
    # clothAllData写入到data\\cloth\\cloth_all.json文件中
    with open('data\\cloth\\cloth_all.json', 'w') as file:
        json.dump(clothAllData, file, indent=4)
        
def genHairs():
    #合并cloth文件
    # 遍历data\\cloth文件夹下的所有文件
    hairAllData = {}
    for filename in os.listdir("data\\hair"):
        if filename.endswith(".json"):
            with open(os.path.join("data\\hair", filename), 'r') as file:
                content = file.read()
                hairData = json.loads(content)
                for key, value in hairData.items():
                    hairAllData[key] = value
                    svgStr = build_svg(hair=value['frontSide'])
                    with open(f'images\\hair\\{key}.svg', 'w') as svgFile:
                        svgFile.write(svgStr)
        
    with open('data\\hair\\hair_all.json', 'w') as file:
        json.dump(hairAllData, file, indent=4)

def genAvatar():
    # female or male: cloth and hair 
    
    # cloth
    clothPath = getCloth('cloth10008')
    
    # eye
    eyePath = getEye('eye20075')
    
    # eyebrow
    eyebrowPath = getEyebrow('eyebrow20013')
    
    # face
    facePath = getFace('face20000')

    # feature
    featurePath = getFeature('feature5')
    
    # glass
    glassPath = getGlass('glass17')
        
    # hair
    hairPath = getHair('hair7')
    
    # hat
    hatPath = getHat('hat20010')
    
    # hobby
    hobbyPath = getHobby('hobby20000')
    
    # mouth
    mouthPath = getMouth('mouth17')
    
    # nose
    nosePath = getNose('nose20037')
    
    svgStr = build_svg(cloth=clothPath)
    
    # print(svgStr)
    with open('E:\\svg\\x.svg', 'w') as svgFile:
        svgFile.write(svgStr)

def genSimpleAvatar():
    # simple avatar with cloth and hair
    facePath = getFace('face20011')
    hairPath = getHair('hair1')
    
    with open("data\\hair\\hair_all.json", 'r') as file:
        hair = file.read()
        hairData = json.loads(hair)
        # 创建一个新的文件夹,多级路径
        os.makedirs(f"images\\simple_avatar\\hair", exist_ok=True)
        for key, value in hairData.items():
            svgStr = build_svg(hair=value['frontSide'], face=facePath)
            with open(f'images\\simple_avatar\\hair\\{key}.svg', 'w') as svgFile:
                svgFile.write(svgStr)
            # os.mkdir(f"images\\simple_avatar\\{key}")
            
    with open("data\\cloth\\cloth_all.json", 'r') as clothFile:
        # 创建一个新的文件夹,多级路径
        os.makedirs(f"images\\simple_avatar\\cloth", exist_ok=True)
        clothData = json.loads(clothFile.read())
        for clothKey, clothValue in clothData.items():
            svgStr = build_svg(hair=hairPath, cloth=clothValue['frontSide']['path'], face=facePath)
            with open(f'images\\simple_avatar\\cloth\\{clothKey}.svg', 'w') as svgFile:
                svgFile.write(svgStr)
        

if __name__ == "__main__":
    genSimpleAvatar()